package cn.demoncat.util.es.util;

import cn.demoncat.util.lang.entity.Pager;
import org.apache.commons.lang3.StringUtils;
import org.elasticsearch.search.aggregations.Aggregations;
import org.elasticsearch.search.aggregations.bucket.terms.Terms;
import org.springframework.data.elasticsearch.annotations.Document;
import org.springframework.data.elasticsearch.core.SearchHit;
import org.springframework.data.elasticsearch.core.SearchHits;
import org.springframework.data.elasticsearch.core.mapping.IndexCoordinates;

import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * ElasticSearch 工具
 * 
 * @author 延晓磊
 *
 * @since 2020-9-3
 */
public class EsUtil {

	// 索引POJO类:索引名
	private static final Map<String, String> indexes = new HashMap<>();

	/**
	 * 获取索引名
	 * 
	 * @param indexClass	索引POJO类
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020年8月31日
	 */
	public static String getIndexName(Class<?> indexClass) {
		// 缓存获取
		String name = indexes.get(indexClass.getName());
		if (name == null) {
			// 通过注解获取
			name = indexClass.getAnnotation(Document.class).indexName();
			if (StringUtils.isBlank(name)) {
				throw new RuntimeException("请给ES-POJO注解Document并指定indexName：" + indexClass);
			}
			// 缓存映射
			indexes.put(indexClass.getName(), name);
		}
		return name;
	}
	
	/**
	 * 获取索引坐标
	 * 
	 * @param indexClass
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020-9-3
	 */
	public static IndexCoordinates getIndexCoordinates(Class<?> indexClass) {
		return IndexCoordinates.of(getIndexName(indexClass));
	}
	
	/**
	 * 获取查询结果
	 * 
	 * @param <T>
	 * @param hits
	 * @return
	 * 
	 * @author 延晓磊
	 *
	 * @since 2020-9-4
	 */
	public static <T>List<T> getList(SearchHits<T> hits){
		return hits.get().map(SearchHit::getContent).collect(Collectors.toList());
	}

	/**
	 * 获取查询高亮
	 *
	 * 注意：高亮字段，必须是分词+被搜索的字段
	 *
	 * @param hits
	 * @return {field:[片段]}
	 *
	 * @author 延晓磊
	 *
	 * @since 2020-9-4
	 */
	public static List<Map<String, List<String>>> getHigh(SearchHits<?> hits){
		return hits.get().map(SearchHit::getHighlightFields).collect(Collectors.toList());
	}

	/**
	 * 获取查询高亮
	 *
	 * 注意：高亮字段，必须是分词+被搜索的字段
	 *
	 * @param hits
	 * @param field
	 * @return [片段]
	 *
	 * @author 延晓磊
	 *
	 * @since 2020-9-4
	 */
	public static List<List<String>> getHigh(SearchHits<?> hits, String field){
		return hits.get().map(o -> o.getHighlightField(field)).collect(Collectors.toList());
	}

	/**
	 * 获取查询高亮
	 *
	 * 场景：1查询分页，2获取高亮，3遍历数据并组装高亮
	 *
	 * 注意：高亮字段，必须是分词+被搜索的字段
	 *
	 * @param page
	 * @return [{field:[片段]}]
	 *
	 * @author 延晓磊
	 *
	 * @since 2020-9-4
	 */
	public static List<Map<String, List<String>>> getHigh(Pager<?> page){
		return getHigh((SearchHits<?>)page.getTemp());
	}

	/**
	 * 获取查询高亮
	 *
	 * 场景：1查询分页，2获取高亮，3遍历数据并组装高亮
	 *
	 * 注意：高亮字段，必须是分词+被搜索的字段
	 *
	 * @param page
	 * @param field
	 * @return [片段]
	 *
	 * @author 延晓磊
	 *
	 * @since 2020-9-4
	 */
	public static List<List<String>> getHigh(Pager<?> page, String field){
		return getHigh((SearchHits<?>)page.getTemp(), field);
	}

	/**
	 * 获取查询聚合
	 *
	 * @param hits
	 * @return 聚合结果
	 *
	 * @author 延晓磊
	 *
	 * @since 2020-9-4
	 */
	public static Aggregations getAgg(SearchHits<?> hits){
		return hits.getAggregations();
	}

	/**
	 * 获取查询聚合
	 *
	 * 场景：1查询分页，2获取聚合，3处理聚合数据
	 *
	 * @param page
	 * @return [{aggName:[片段]}]
	 *
	 * @author 延晓磊
	 *
	 * @since 2020-9-4
	 */
	public static Aggregations getAgg(Pager<?> page){
		return getAgg((SearchHits<?>)page.getTemp());
	}

	/**
	 * 获取查询聚合-词条桶
	 *
	 * 场景：1查询分页，2获取聚合，3处理聚合数据
	 *
	 * @param page
	 * @param aggName
	 * @return [{field:[片段]}]
	 *
	 * @author 延晓磊
	 *
	 * @since 2020-9-4
	 */
	public static List<? extends Terms.Bucket> getAgg(Pager<?> page, String aggName){
		return AggregationUtil.getTerms(getAgg(page), aggName);
	}

	/**
	 * 获取查询嵌套聚合
	 *
	 * 场景：1查询分页，2获取聚合，3处理聚合数据
	 *
	 * @param page
	 * @param aggName
	 * @return [{field:[片段]}]
	 *
	 * @author 延晓磊
	 *
	 * @since 2020-9-4
	 */
	public static Aggregations getNestedAgg(Pager<?> page, String aggName){
		return AggregationUtil.getNested(getAgg(page), aggName);
	}

	/**
	 * 获取查询嵌套聚合-词条桶
	 *
	 * 场景：1查询分页，2获取聚合，3处理聚合数据
	 *
	 * @param page
	 * @param nestedAggName
	 * @param aggName
	 * @return [{field:[片段]}]
	 *
	 * @author 延晓磊
	 *
	 * @since 2020-9-4
	 */
	public static List<? extends Terms.Bucket> getNestedAgg(Pager<?> page, String nestedAggName, String aggName){
		return AggregationUtil.getTerms(getNestedAgg(page, nestedAggName), aggName);
	}
}
